package service

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/cdsailyj/go-vpn/common/tool"
	"gitee.com/cdsailyj/go-vpn/common/util/vpn"
	"gitee.com/cdsailyj/go-vpn/forms"
	"gitee.com/cdsailyj/go-vpn/global"
	"github.com/go-vgo/robotgo"
	"github.com/gorilla/websocket"
	"github.com/kbinani/screenshot"
	"image/jpeg"
	"strconv"
	"time"

	"golang.org/x/net/context"
	"log"
	"net/url"
)

type RobotService struct {
	Clients  map[string]*VpnClient
	MyClient *VpnClient
}

// 客户端
type VpnClient struct {
	UserId          string                  `json:"user_id" form:"user_id" binding:"required"`
	Ip              string                  `json:"ip" form:"ip"`
	DisplayNum      int                     `json:"display_num" form:"display_num"`
	DisplayCurrent  int                     `json:"display_current" form:"display_current"`
	FPS             int                     `json:"fps" form:"fps"`
	Quality         int                     `json:"quality" form:"quality"`
	ControlFlag     bool                    `json:"control_flag" form:"control_flag"`
	Online          bool                    `json:"online" form:"online"`
	ControlBy       string                  `json:"control_by" form:"control_by"`
	LastFrame       []byte                  `json:"-" form:"last_frame"`
	LastFrameBase64 string                  `json:"last_frame_base64" form:"last_frame_base64"`
	CmdChanLength   int                     `json:"cmd_chan_length" form:"cmd_chan_length"`
	CmdChan         chan vpn.ControlCommand `json:"-" form:"cmd_chan"`
	Screens         []vpn.Screen            `db:"screens" json:"screens" form:"screens"`
	ConnControlGet  *websocket.Conn         `json:"-"`
	ctx             context.Context         `json:"-"`
	cancel          context.CancelFunc      `json:"-"`
}

func (r *RobotService) GetClient(userId string) *VpnClient {
	_, ok := r.Clients[userId]
	if !ok {
		r.Clients[userId] = NewVpnClient(userId)
	}
	return r.Clients[userId]
}

func (r *RobotService) InitMyClient() {
	if r.MyClient != nil && r.MyClient.Online {
		return
	}
	set, _ := ServiceGroupApp.SettingService.GetSetting()
	if len(set.UserId) > 0 {
		c, err := r.StartClient(set.UserId)
		if err != nil {
			panic(err)
		}
		r.MyClient = c
	}
}

func (r *RobotService) StartClient(userId string) (*VpnClient, error) {
	c := NewVpnClient(userId)
	c.Screens = vpn.GetScreens()
	c.Online = true
	c.DisplayCurrent = 0
	c.FPS = 1 // 1秒1帧
	c.Quality = 30
	c.DisplayNum = screenshot.NumActiveDisplays()
	c.ControlFlag = false
	c.ControlBy = ""

	preview, _ := c.GetScreenPreview(0, 50)
	c.LastFrameBase64 = preview

	c.ListenCmd()

	_, err := c.SyncClientToServer()
	if err != nil {
		return nil, err
	}
	return c, nil
}

func NewVpnClient(userId string) *VpnClient {
	return &VpnClient{
		UserId:         userId,
		DisplayNum:     0,
		DisplayCurrent: 0,
		Screens:        make([]vpn.Screen, 0),
		CmdChan:        make(chan vpn.ControlCommand),
		LastFrame:      make([]byte, 0),
		ControlFlag:    false,
		Online:         false,
	}
}

func (c *VpnClient) SyncClientToServer() (bool, error) {
	apiUrl := fmt.Sprintf("http://%s/vpn/sync", global.CONFIG.VpnWsDomain)
	contents, _, err := tool.HttpPostJson(apiUrl, c, nil)
	if err != nil {
		return false, err
	}
	var data forms.AjaxResult[any]
	if err = json.Unmarshal(contents, &data); err != nil {
		return false, err
	}
	if data.Code != 0 {
		return false, errors.New(data.Msg)
	}
	return true, nil
}

func (c *VpnClient) Stop() error {
	if c.cancel != nil {
		c.ControlFlag = false
		c.ControlBy = ""
		c.cancel()
		//c.ConnControlGet.Close()
		//close(c.CmdChan)

		_, err := c.SyncClientToServer()
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *VpnClient) ShareAndControl(controlBy string) error {
	if len(c.ControlBy) > 0 && c.cancel != nil {
		c.Stop()
	}
	c.ControlFlag = true
	c.ControlBy = controlBy
	_, err := c.SyncClientToServer()
	if err != nil {
		return err
	}

	// 上传屏幕数据的URL
	// 启动屏幕捕获上传
	go c.CaptureAndUpload()

	return nil
}

// 创建命令通道
func (c *VpnClient) ListenCmd() {
	c.CmdChan = make(chan vpn.ControlCommand)
	go c.HandleCommands()
	go c.ReadCmdFromServer()
}

func (c *VpnClient) SetNewFrame(frame []byte) {
	c.LastFrame = frame
}

func (c *VpnClient) PushCmd(msg vpn.ControlCommand) {
	c.CmdChan <- msg
}

func (c *VpnClient) HandleCommands() {
	defer close(c.CmdChan)

	for {
		select {
		//case <-c.ctx.Done():
		//	fmt.Println("HandleCommands 进程终止")
		//	return
		case cmd := <-c.CmdChan:
			fmt.Sprintf("执行命令: %v \n", cmd)
			c.ExecCmd(cmd)
		}
	}

}

func (c *VpnClient) ExecCmd(cmd vpn.ControlCommand) {
	switch cmd.Type {
	case "mousemove":
		robotgo.Move(cmd.X, cmd.Y)
	case "mouseclick":
		robotgo.Move(cmd.X, cmd.Y)
		if cmd.Key == "left" {
			robotgo.Click()
			fmt.Println("点击左键")
		} else {
			robotgo.Click("right")
			fmt.Println("点击右键")
		}

	case "keyboard":
		robotgo.KeyTap(cmd.Key)
	case "start": //开启屏幕共享
		c.ShareAndControl(cmd.Key)
	case "stop": //停止屏幕共享
		c.Stop()
	case "fps": //修改FPS
		FPS, err := strconv.Atoi(cmd.Key)
		if err == nil {
			c.FPS = FPS
		}
	case "quality": //修改截图质量
		quality, err := strconv.Atoi(cmd.Key)
		if err == nil {
			c.Quality = quality
		}
	case "screen": //切换屏幕
		display, err := strconv.Atoi(cmd.Key)
		if err == nil {
			c.DisplayCurrent = display
		}
	}
}

// 抓取显示器缩略图
func (c *VpnClient) GetScreenPreview(screenIndex int, quality int) (string, error) {
	contents, err := c.CaptureScreen(screenIndex, quality) //捕获第几个屏幕
	imgBytes, err := tool.ResizeImg(contents, 80, 320, 180)
	if err != nil {
		return "", err
	}
	return tool.Base64Encode(imgBytes), nil
}

// 抓取显示器
func (c *VpnClient) CaptureScreen(screenIndex int, quality int) ([]byte, error) {
	img, err := screenshot.CaptureDisplay(screenIndex) //捕获第几个屏幕
	if err != nil {
		return nil, err
	}
	buf := new(bytes.Buffer)
	err = jpeg.Encode(buf, img, &jpeg.Options{
		Quality: quality,
	})
	return buf.Bytes(), nil
}

// 抓取显示器并上传
func (c *VpnClient) CaptureAndUpload() {
	//interval := time.Second / time.Duration(c.FPS) // 正确计算每帧间隔
	ctx, cancel := context.WithCancel(context.Background())
	c.ctx = ctx
	c.cancel = cancel

	serverURL := fmt.Sprintf("ws://%s/frame-put?userId=%s", global.CONFIG.VpnWsDomain, c.UserId)
	u, _ := url.Parse(serverURL)
	dialer := tool.GetWebsocketDialer(u.Host)
	conn, _, err := dialer.Dial(u.String(), nil)
	if err != nil {
		log.Fatal("CaptureAndUpload DialErr:", err)
	}
	defer conn.Close()

	ticker := time.NewTicker(time.Second / time.Duration(c.FPS)) // 1秒1帧
	defer ticker.Stop()

	for {
		select {
		case <-c.ctx.Done():
			fmt.Println("CaptureAndUpload 停止共享屏幕")
			return
		case <-ticker.C:
			// 捕获屏幕
			start := time.Now()
			img, err := screenshot.CaptureDisplay(c.DisplayCurrent) //捕获第几个屏幕
			if err != nil {
				// 处理错误
				continue
			}
			captureTime := time.Since(start)

			// 压缩为JPEG
			start = time.Now()
			buf := new(bytes.Buffer)
			err = jpeg.Encode(buf, img, &jpeg.Options{
				Quality: c.Quality,
			})
			encodeTime := time.Since(start)

			if err != nil {
				// 处理错误
				continue
			}

			// 连接控制WebSocket
			start = time.Now()
			err = conn.WriteMessage(websocket.BinaryMessage, buf.Bytes())
			websocketTime := time.Since(start)

			if err != nil {
				fmt.Printf("上传屏幕图片失败: %#v \n", err)
				c.Stop()
			}

			// 总耗时
			totalTime := captureTime + encodeTime + websocketTime

			fmt.Printf("各阶段耗时 - 截图: %v, 编码: %v, 传输: %v, 总大小: %v, 总耗时: %v\n", captureTime, encodeTime, websocketTime, len(buf.Bytes()), totalTime)
		}
	}
}

func (c *VpnClient) ConnectToControlServer() (*websocket.Conn, error) {
	// 控制指令的WebSocket URL
	serverURL := fmt.Sprintf("ws://%s/control-get?userId=%s", global.CONFIG.VpnWsDomain, c.UserId)

	// 连接控制WebSocket
	u, _ := url.Parse(serverURL)
	dialer := tool.GetWebsocketDialer(u.Host)
	conn, _, err := dialer.Dial(u.String(), nil)
	if err != nil {
		log.Printf("ConnectToControlServer 连接控制服务器失败:%v \n", err)
		return nil, err
	}
	log.Println("ConnectToControlServer 开始监听制服务器的命令")
	return conn, nil
}

func (c *VpnClient) ReadCmdFromServer() {
	conn, err := c.ConnectToControlServer()
	if err != nil {
		return
	}
	defer conn.Close()

	// 只在第一次链接服务器的时候，创建心跳检测的定时器，不能重复添加
	isFirst := c.ConnControlGet == nil
	c.ConnControlGet = conn

	if isFirst {
		go func() {
			// 心跳检测
			ticker := time.NewTicker(30 * time.Second)
			defer ticker.Stop()
			for {
				select {
				case <-ticker.C:
					err = c.ConnControlGet.WriteMessage(websocket.TextMessage, []byte("ping"))
					if err != nil {
						log.Printf("心跳检测失败，重新发起连接: %v \n", err)
						c.ReadCmdFromServer()
					}
				}
			}
		}()
	}

	// 主循环
	for {
		_, message, err := c.ConnControlGet.ReadMessage()
		if err != nil {
			log.Println("Websocket ReadMessage 错误，ReadCmdFromServer 进程终止:", err)
			return
		}
		// 将接收到的命令发送到处理通道
		var cmd vpn.ControlCommand
		err = json.Unmarshal(message, &cmd)
		if err != nil {
			continue
		}
		log.Printf("收到命令参数: %v\n", cmd)
		c.CmdChan <- cmd
	}
}
